home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 January: Mac OS SDK / Dev.CD Jan 96 SDK / Dev.CD Jan 96 SDK1.toast / Development Kits (Disc 1) / AOCE / Development Tools / Sample Code / Messaging Service Access Module / Internet PMSAM / Template source / Internet Setup Template / InternetMailService.code.c next >
Encoding:
C/C++ Source or Header  |  1993-10-29  |  45.0 KB  |  1,603 lines  |  [TEXT/MPS ]

  1. /*
  2.  
  3.   --------------------------------------------------------------------
  4.   Internet Personal MSAM Sample Setup Template Code
  5.   1.0b9 version
  6.   
  7.   Steve Falkenburg
  8.   MacDTS 7/22/93
  9.   AppleLink DEVSUPPORT for questions (if you're a supported seed site)  
  10.   --------------------------------------------------------------------
  11.   
  12.   *********** WARNING ***************
  13.   
  14.   DO NOT USE MPW C 3.3 TO COMPILE THIS TEMPLATE.  IT HAS A BUG WHICH CAUSES
  15.   STRING LITERALS CONTAINING \0 TO NOT COMPILE PROPERLY.  INSTEAD, YOU SHOULD
  16.   USE MPW C 3.2.4, WHICH DOESN'T HAVE THIS BUG.
  17.   
  18.   *********** WARNING ***************
  19. */
  20.  
  21. #include <Types.h>
  22. #include <Memory.h>
  23. #include <Dialogs.h>
  24. #include <Resources.h>
  25. #include <String.h>
  26. #include <Strings.h>
  27.  
  28. #include <OCE.h>
  29. #include <OCEAuthDir.h>
  30. #include <OCEMail.h>
  31. #include <OCETemplates.h>
  32. #include <OCEErrors.h>
  33.  
  34. #include "InternetMailService.code.h"
  35. #include "InternetProperties.h"
  36.  
  37. //---------------------------------------------------------------------------------------
  38.  
  39. pascal OSErr MailServiceCode(DETCallBlockPtr callBlockPtr)
  40. {
  41.     OSErr err;
  42.     
  43.     // handle the callback if we've got our data or if it's the initial call
  44.     
  45.     if (((callBlockPtr->protoCall.target.selector==kDETSelf) && ((callBlockPtr->protoCall.instancePrivate!=nil) ||
  46.             (callBlockPtr->protoCall.reqFunction == kDETcmdInstanceInit))) ||
  47.             (callBlockPtr->protoCall.reqFunction == kDETcmdInit)) {
  48.         
  49.         // handle the different callbacks
  50.         
  51.         switch (callBlockPtr->protoCall.reqFunction) {
  52.             case kDETcmdInit:
  53.                 err = InitTemplate(callBlockPtr);
  54.                 break;
  55.             case kDETcmdInstanceInit:                    // Template instance initialization
  56.                 err = InitInstance(callBlockPtr);
  57.                 break;
  58.             case kDETcmdInstanceExit:                    // Template exit- dispose memory
  59.                 err = ExitInstance(callBlockPtr);        
  60.                 break;
  61.             case kDETcmdValidateSave:                    // about to save an info-page
  62.                 err = ValidateSave(callBlockPtr);
  63.                 break;
  64.             case kDETcmdPropertyCommand:                // property command (item hit)
  65.                 err = PropertyItemHit(callBlockPtr);
  66.                 break;
  67.             default:
  68.                 err = kDETDidNotHandle;
  69.                 break;
  70.         }
  71.     }
  72.     else err = kDETDidNotHandle;
  73.     
  74.     if (err<noErr)
  75.         DoError(err);
  76.     
  77.     return err;
  78. }
  79.  
  80. //---------------------------------------------------------------------------------------
  81.  
  82. OSErr InitTemplate(DETCallBlockPtr callBlockPtr)
  83. {
  84.     DETCallBackBlock callBack;
  85.     OSErr err;
  86.  
  87.     TraceExecution("\pInitTemplate");
  88.     
  89.     callBack.changeCallFors.reqFunction = kDETcmdChangeCallFors;
  90.     callBack.changeCallFors.target.selector = kDETSelf;
  91.     callBack.changeCallFors.newCallFors = callBlockPtr->init.newCallFors | kDETCallForValidation;
  92.     err = CallBackDET(callBlockPtr, &callBack);
  93.             
  94.     return err;
  95. }
  96.  
  97.  
  98. OSErr InitInstance(DETCallBlockPtr callBlockPtr)
  99. {
  100.     GlobalData *globalData;
  101.     DETCallBackBlock callBack;
  102.     OSErr err;
  103.     PackedRecordID assocDir;
  104.     RecordID assocDirUnpacked;
  105.     CreationID attrCID;
  106.     
  107.     TraceExecution("\pInitInstance");
  108.     
  109.     err = CheckFileIDs(callBlockPtr);
  110.     if (err!=noErr)
  111.         return err;
  112.  
  113.     if (callBlockPtr->protoCall.instancePrivate)
  114.         return kInternalError;
  115.         
  116.     globalData = (GlobalData *)NewPtr(sizeof(GlobalData));
  117.     if (MemError()!=noErr)
  118.         return MemError();
  119.     
  120.     callBlockPtr->protoCall.instancePrivate = globalData;
  121.     
  122.     // get our DSSpec and CID and OCESetup dsRefNum
  123.  
  124.     callBack.getDSSpec.reqFunction = kDETcmdGetDSSpec;
  125.     callBack.getDSSpec.target.selector = kDETSelf;
  126.     err = CallBackDET(callBlockPtr, &callBack);
  127.     if (err!=noErr)
  128.         return err;
  129.     globalData->oceSetupDSRef = callBack.getDSSpec.refNum;
  130.     HLock((Handle)callBack.getDSSpec.dsSpec);
  131.     GetCreationIDFromDSSpec(*callBack.getDSSpec.dsSpec,&globalData->mailCID);
  132.     DisposHandle((Handle)callBack.getDSSpec.dsSpec);    
  133.     
  134.     // get directoryCID
  135.     
  136.     err = GetSingleValueAttribute(&globalData->mailCID,globalData->oceSetupDSRef,
  137.         OCEGetIndAttributeType(kAssoDirectoryAttrTypeNum),&assocDir,sizeof(PackedRecordID),&attrCID);
  138.     if (err!=noErr)
  139.         return err;
  140.     OCEUnpackRecordID(&assocDir,&assocDirUnpacked);
  141.     OCECopyCreationID(&assocDirUnpacked.local.cid,&globalData->directoryCID);
  142.     
  143.     // read data out of slot,directory records
  144.     
  145.     err = GetMailSlotInfo(globalData->oceSetupDSRef,&globalData->mailCID,
  146.             &globalData->config,&globalData->hasBeenCreated);
  147.     if (err!=noErr)
  148.         return err;
  149.         
  150.     err = GetDirectoryInfo(globalData->oceSetupDSRef,&globalData->directoryCID,
  151.             &globalData->config,&globalData->fakeDirectory);
  152.     if (err!=noErr)
  153.         return err;
  154.         
  155.     // store data into info page if we're modifying an existing record
  156.     
  157.     if (globalData->hasBeenCreated) {
  158.         err = SetInfoPageInformation(callBlockPtr,&globalData->config);
  159.         if (err!=noErr)
  160.             return err;
  161.         err = UpdateDisplayNames(callBlockPtr,globalData);
  162.         if (err!=noErr)
  163.             return err;
  164.     }
  165.             
  166.     return err;
  167. }
  168.  
  169.  
  170. OSErr ExitInstance(DETCallBlockPtr callBlockPtr)
  171. {
  172.     GlobalData *globalData;
  173.     
  174.     TraceExecution("\pExitInstance");
  175.  
  176.     globalData = (GlobalData *)callBlockPtr->protoCall.instancePrivate;
  177.     if (globalData==0L)
  178.         return kInternalError;
  179.         
  180.     DisposPtr((Ptr)globalData);
  181.     if (MemError()!=noErr)
  182.         return MemError();
  183.         
  184.     callBlockPtr->protoCall.instancePrivate = 0;
  185.  
  186.     return noErr;
  187. }
  188.  
  189.  
  190. //---------------------------------------------------------------------------------------
  191.  
  192.  
  193. OSErr ValidateSave(DETCallBlockPtr callBlockPtr)
  194. {
  195.     GlobalData *globalData;
  196.     OSErr err;
  197.     
  198.     TraceExecution("\pValidateSave");
  199.                 
  200.     // read the information out of the info page (we need this to do the exitinstance anyway...
  201.     
  202.     globalData = (GlobalData *)callBlockPtr->protoCall.instancePrivate;
  203.     if (globalData==0L)
  204.         return kInternalError;
  205.  
  206.     if (HasBeenChanged(callBlockPtr,&globalData->config)) {
  207.     
  208.         err = GetInfoPageInformation(callBlockPtr,&globalData->config);
  209.         if (err!=noErr)
  210.             return err;
  211.             
  212.         if (globalData->hasBeenCreated)
  213.             err = ModifyOurSlot(callBlockPtr,globalData);
  214.         else {
  215.             err = CreateOurSlot(callBlockPtr,globalData);
  216.             if (err==noErr)
  217.                 globalData->hasBeenCreated = true;
  218.         }
  219.         err = UpdateDisplayNames(callBlockPtr,globalData);
  220.     }
  221.     
  222.     return err;
  223. }
  224.  
  225.  
  226. //---------------------------------------------------------------------------------------
  227.  
  228.  
  229. OSErr PropertyItemHit(DETCallBlockPtr callBlockPtr)
  230. {
  231.     GlobalData *globalData;
  232.     OSErr err;
  233.     
  234.     TraceExecution("\pPropertyItemHit");
  235.     
  236.     globalData = (GlobalData *)callBlockPtr->protoCall.instancePrivate;
  237.     if (globalData==0L)
  238.         return kInternalError;    
  239.  
  240.     switch (callBlockPtr->propertyCommand.property) {
  241.         case kPrSetPassword:
  242.             err = SetUserPassword(globalData->config.dirIdentity.password);
  243.             if (err==noErr)
  244.                 DirtyProperty(callBlockPtr, kPrSetPassword);
  245.             break;
  246.         default:
  247.             err = kInternalError;
  248.             break;
  249.     }
  250.     
  251.     return err;
  252. }
  253.  
  254.  
  255. //---------------------------------------------------------------------------------------
  256. //---------------------------------------------------------------------------------------
  257.  
  258.  
  259. OSErr CheckFileIDs(DETCallBlockPtr callBlockPtr)
  260. {
  261.     OSErr err;
  262.     CreationID msamCID,attrCID;
  263.     long fileID,oldFileID;
  264.     DirGetOCESetupRefNumPB pBlock;
  265.     short dsRefNum;
  266.     
  267.     TraceExecution("\pCheckFileIDs");
  268.  
  269.     // see if the MSAM record exists
  270.         
  271.     pBlock.identity = kIdentity;
  272.     err = DirGetOCESetupRefNum((DirParamBlockPtr)&pBlock,false);
  273.     if (err!=noErr)
  274.         return err;
  275.     dsRefNum = pBlock.dsRefNum;
  276.     
  277.     err = GetSingleRecord(dsRefNum,OCEGetIndRecordType(kMSAMRecTypeNum),kMSAMRecordName,&msamCID);
  278.     if (err==noErr) {
  279.     
  280.         // make sure that the file ID attribute is still valid.  If not, replace it, since the user may have upgraded
  281.         // from an older version of the MSAM.
  282.         
  283.         err = GetFileID(callBlockPtr,&fileID);
  284.         if (err!=noErr)
  285.             return err;
  286.         GetSingleValueAttribute(&msamCID,dsRefNum,OCEGetIndAttributeType(kGatewayFileIDAttrTypeNum),
  287.                         &oldFileID,sizeof(long),&attrCID);
  288.         if (err!=noErr)
  289.             return err;
  290.         if (oldFileID!=fileID) {
  291.             TraceExecution("\pUpdateFileID");
  292.             err = ChangeSingleAttribute(&msamCID,dsRefNum,OCEGetIndAttributeType(kGatewayFileIDAttrTypeNum),
  293.                     &fileID,sizeof(long),typeBinary);
  294.             if (err!=noErr)
  295.                 return err;
  296.         }
  297.     }
  298.     else err = noErr;
  299.     
  300.     return err;
  301. }
  302.  
  303.  
  304. OSErr GetMailSlotInfo(short dsRef,const CreationID *mailCID,ConfigInformation *config,Boolean *hasBeenCreated)
  305. {
  306.     PackedRecordID parentMSAM;
  307.     CreationID attrCID;
  308.     OSErr err;
  309.         
  310.     // check for parentmsam attribute, and set has been created flag
  311.  
  312.     err = GetSingleValueAttribute(mailCID,dsRef,OCEGetIndAttributeType(kParentMSAMAttrTypeNum),&parentMSAM,
  313.             sizeof(PackedRecordID),&attrCID);
  314.     if (err==noErr)
  315.         *hasBeenCreated = true;
  316.     else
  317.         *hasBeenCreated = false;
  318.     err = noErr;
  319.     
  320.     if (*hasBeenCreated) {
  321.         // read standard slot info (don't check errors, since it may not exist yet...
  322.     
  323.         err = GetSingleValueAttribute(mailCID,dsRef,OCEGetIndAttributeType(kStdSlotInfoAttrTypeNum),
  324.                 &config->stdInfo,sizeof(MailStandardSlotInfoAttribute),&attrCID);
  325.         if (err!=noErr)
  326.             return err;
  327.             
  328.         // read specific slot info
  329.     
  330.         GetSingleValueAttribute(mailCID,dsRef,kSetupAttr,&config->specInfo,sizeof(SpecificSlotInfo),&attrCID);
  331.         if (err!=noErr)
  332.             return err;
  333.     }
  334.     else {
  335.         config->stdInfo.version = kStdSlotInfoVersion;
  336.         config->stdInfo.active = 0xff;    // change for b3: make all "i'm at" locations active
  337.         config->stdInfo.sendReceiveTimer.sendTimeKind = kMailTimerFrequency;
  338.         config->stdInfo.sendReceiveTimer.receiveTimeKind = kMailTimerFrequency;
  339.         err = noErr;
  340.     }
  341.     
  342.     return err;
  343. }
  344.  
  345.  
  346. OSErr GetDirectoryInfo(short dsRef,const CreationID *directoryCID,ConfigInformation *config,Boolean *directoryIsFake)
  347. {
  348.     OSErr err;
  349.     OCESetupGetDirectoryInfoPB authBlock;
  350.     CreationID attrCID;
  351.     DirDiscriminator discriminator = {kDirectoryOSType,0};
  352.     PackedRLI pRLI;
  353.     RecordID identRID;
  354.     RString ridName,ridType;
  355.     RString rsNativeName,rsPassword;
  356.     long fake;
  357.     
  358.     // set flag indicating if directory is fake
  359.  
  360.     err = GetSingleValueAttribute(directoryCID,dsRef,OCEGetIndAttributeType(kFakeAttrTypeNum),&fake,sizeof(long),&attrCID);
  361.     if (err==noErr) {
  362.         *directoryIsFake = true;
  363.     }
  364.     else {
  365.         *directoryIsFake = false;
  366.     }
  367.  
  368.     // read ocesetupdirectoryinfo
  369.  
  370.     rsNativeName.charSet = smRoman;
  371.     rsNativeName.dataLength = kRStringMaxChars;
  372.     rsPassword.charSet = smRoman;
  373.     rsPassword.dataLength = kRStringMaxChars;
  374.     ridName.charSet = smRoman;
  375.     ridName.dataLength = kRStringMaxChars;
  376.     ridType.charSet = smRoman;
  377.     ridType.dataLength = kRStringMaxChars;
  378.     pRLI.dataLength = 0;
  379.     identRID.rli = &pRLI;
  380.     OCESetCreationIDtoNull(&identRID.local.cid);
  381.     identRID.local.recordName = &ridName;
  382.     identRID.local.recordType = &ridType;
  383.  
  384.     authBlock.directoryName = kDirectoryName;
  385.     authBlock.discriminator = discriminator;
  386.     authBlock.recordID = &identRID;
  387.     authBlock.nativeName = &rsNativeName;
  388.     authBlock.password = &rsPassword;
  389.     err = OCESetupGetDirectoryInfo((AuthParamBlockPtr)&authBlock,false);
  390.  
  391.     if (err==noErr) {
  392.         strcpy(config->dirIdentity.userName,p2cstr(OCERToPString(&ridName)));
  393.         strcpy(config->dirIdentity.password,p2cstr(OCERToPString(&rsPassword)));
  394.     }
  395.     else {
  396.         // if we don't have an identity yet, zero out name,password
  397.         config->dirIdentity.userName[0] = 0;
  398.         config->dirIdentity.password[0] = 0;
  399.     }
  400.     
  401.     // setup oldpassword field for changes
  402.     
  403.     strcpy(config->dirIdentity.oldPassword,config->dirIdentity.password);
  404.     
  405.     return noErr;    // even if the getdirectory info call failed, we should continue
  406. }
  407.  
  408. //---------------------------------------------------------------------------------------
  409. //---------------------------------------------------------------------------------------
  410.  
  411.  
  412. // store information from config information into info page properties
  413.  
  414. OSErr SetInfoPageInformation(DETCallBlockPtr callBlockPtr,ConfigInformation *config)
  415. {
  416.     RString rstr;
  417.     OSErr err;
  418.  
  419.     // login name
  420.     OCECToRString(config->dirIdentity.userName, smRoman, &rstr, kRStringMaxChars);
  421.     err = SetStringProperty(callBlockPtr, &rstr, kPrLoginName);
  422.     if (err!=noErr)
  423.         return err;
  424.     
  425.     // password
  426.     // handled directly
  427.     
  428.     // pop server
  429.     OCECToRString(config->specInfo.popServer, smRoman, &rstr, kRStringMaxChars);
  430.     err = SetStringProperty(callBlockPtr, &rstr, kPrPopServer);
  431.     if (err!=noErr)
  432.         return err;
  433.     
  434.     // smtp server
  435.     OCECToRString(config->specInfo.smtpServer, smRoman, &rstr, kRStringMaxChars);
  436.     err = SetStringProperty(callBlockPtr, &rstr, kPrSMTPServer);
  437.     if (err!=noErr)
  438.         return err;
  439.     
  440.     // sendtime
  441.     err = SetNumProperty(callBlockPtr, kPrSendTime, config->stdInfo.sendReceiveTimer.send.frequency);
  442.     if (err!=noErr)
  443.         return err;
  444.     
  445.     // recvtime
  446.     err = SetNumProperty(callBlockPtr, kPrRecvTime, config->stdInfo.sendReceiveTimer.receive.frequency);
  447.     if (err!=noErr)
  448.         return err;
  449.     
  450.     return err;
  451. }
  452.  
  453.  
  454. // read information out of info page and store it in config information
  455.  
  456. OSErr GetInfoPageInformation(DETCallBlockPtr callBlockPtr,ConfigInformation *config)
  457. {
  458.     RString rstr;
  459.     OSErr err;
  460.     
  461.     // login name
  462.     err = GetStringProperty(callBlockPtr, kPrLoginName, &rstr);
  463.     if (err!=noErr)
  464.         return err;
  465.     strcpy(config->dirIdentity.userName,p2cstr(OCERToPString(&rstr)));
  466.     
  467.     // password
  468.     // handled directly
  469.     
  470.     // pop server
  471.     err = GetStringProperty(callBlockPtr, kPrPopServer, &rstr);
  472.     if (err!=noErr)
  473.         return err;
  474.     strcpy(config->specInfo.popServer,p2cstr(OCERToPString(&rstr)));
  475.  
  476.     // smtp server
  477.     err = GetStringProperty(callBlockPtr, kPrSMTPServer, &rstr);
  478.     if (err!=noErr)
  479.         return err;
  480.     strcpy(config->specInfo.smtpServer,p2cstr(OCERToPString(&rstr)));
  481.  
  482.     // sendtime
  483.     err = GetNumProperty(callBlockPtr, kPrSendTime, &config->stdInfo.sendReceiveTimer.send.frequency);
  484.     if (err!=noErr)
  485.         return err;
  486.     
  487.     // recvtime
  488.     err = GetNumProperty(callBlockPtr, kPrRecvTime, &config->stdInfo.sendReceiveTimer.receive.frequency);
  489.     if (err!=noErr)
  490.         return err;
  491.     
  492.     return err;
  493. }
  494.  
  495.  
  496. Boolean HasBeenChanged(DETCallBlockPtr callBlockPtr,ConfigInformation *config)
  497. {
  498.     ConfigInformation newConfig;
  499.     OSErr err;
  500.     
  501.     // get new config info
  502.     
  503.     err = GetInfoPageInformation(callBlockPtr,&newConfig);
  504.     if (err!=noErr)
  505.         return true; // return changed to catch error later
  506.     
  507.     // check std slot information
  508.     
  509.     if (newConfig.stdInfo.sendReceiveTimer.send.frequency != config->stdInfo.sendReceiveTimer.send.frequency)
  510.         return true;
  511.     if (newConfig.stdInfo.sendReceiveTimer.receive.frequency != config->stdInfo.sendReceiveTimer.receive.frequency)
  512.         return true;
  513.     
  514.     // check specific slot information
  515.     
  516.     if (strcmp(newConfig.specInfo.popServer,config->specInfo.popServer)!=0)
  517.         return true;
  518.     if (strcmp(newConfig.specInfo.smtpServer,config->specInfo.smtpServer)!=0)
  519.         return true;
  520.  
  521.     // check identity
  522.     
  523.     if (strcmp(newConfig.dirIdentity.userName,config->dirIdentity.userName)!=0)
  524.         return true;
  525.     if (strcmp(config->dirIdentity.oldPassword,config->dirIdentity.password)!=0)
  526.         return true;
  527.  
  528.     return false;
  529. }
  530.  
  531.  
  532. OSErr UpdateDisplayNames(DETCallBlockPtr callBlockPtr,GlobalData *globalData)
  533. {
  534.     OSErr err;
  535.     RString rstr;
  536.     
  537.     // rename mailservice record to pop server
  538.     
  539.     OCECToRString(globalData->config.specInfo.popServer, smRoman, &rstr, kRStringMaxChars);
  540.     err = SetRecNameAndType(&globalData->mailCID,globalData->oceSetupDSRef,&rstr,kMailServiceType);
  541.     if (err!=noErr)
  542.         return err;
  543.     
  544.     // set aspect name property to pop server
  545.     
  546.     OCECToRString(globalData->config.specInfo.popServer, smRoman, &rstr, kRStringMaxChars);
  547.     err = SetStringProperty(callBlockPtr, &rstr, kDETAspectName);
  548.     if (err!=noErr)
  549.         return err;
  550.         
  551.     // set aspect user name property to account name
  552.  
  553.     OCECToRString(globalData->config.dirIdentity.userName, smRoman, &rstr, kRStringMaxChars);
  554.     err = SetStringProperty(callBlockPtr, &rstr, kSAMAspectUserName);
  555.     if (err!=noErr)
  556.         return err;
  557.         
  558.     err = RequestSync(callBlockPtr);
  559.     return err;
  560. }
  561.  
  562.  
  563. //---------------------------------------------------------------------------------------
  564. //---------------------------------------------------------------------------------------
  565.  
  566.  
  567. // GetStringProperty
  568. //
  569. // gets a string property from the DE template and returns it to us as an RString
  570. //
  571. OSErr GetStringProperty(DETCallBlockPtr callBlockPtr, short property, RString *str)
  572. {
  573.     OSErr err;
  574.     DETCallBackBlock callBack;
  575.     
  576.     callBack.getPropertyRString.reqFunction = kDETcmdGetPropertyRString;
  577.     callBack.getPropertyRString.property = property;
  578.     callBack.getPropertyRString.target.selector = kDETSelf;
  579.     err = CallBackDET(callBlockPtr, &callBack);
  580.     
  581.     if (err==noErr) {
  582.         BlockMove((Ptr)*(callBack.getPropertyRString.propertyValue), (Ptr)str, 
  583.                 (**(callBack.getPropertyRString.propertyValue)).dataLength+sizeof(ProtoRString));
  584.         DisposHandle((Handle)callBack.getPropertyRString.propertyValue);
  585.     }
  586.     
  587.     return err;
  588. }
  589.  
  590.  
  591. // SetStringProperty
  592. //
  593. // sets a DET string property to a value that we pass it
  594. //
  595. OSErr SetStringProperty(DETCallBlockPtr callBlockPtr, RString *string, short property)
  596. {
  597.     OSErr err;
  598.     DETCallBackBlock callBack;
  599.         
  600.     callBack.setPropertyRString.reqFunction = kDETcmdSetPropertyRString;
  601.     callBack.setPropertyRString.property = property;
  602.     callBack.setPropertyRString.target.selector = kDETSelf;
  603.     callBack.setPropertyRString.newValue = string;
  604.     err = CallBackDET(callBlockPtr, &callBack);
  605.  
  606.     if (err==noErr)
  607.         err = DirtyProperty(callBlockPtr, property);
  608.     
  609.     return err;
  610. }
  611.  
  612.  
  613. // SetNumProperty
  614. //
  615. // sets a DET number property to a value that we pass it
  616. //
  617. OSErr SetNumProperty(DETCallBlockPtr callBlockPtr, short property, long value)
  618. {
  619.     OSErr err;
  620.     DETCallBackBlock callBack;
  621.     
  622.     callBack.setPropertyNumber.reqFunction = kDETcmdSetPropertyNumber;
  623.     callBack.setPropertyNumber.property = property;
  624.     callBack.setPropertyNumber.target.selector = kDETSelf;
  625.     callBack.setPropertyNumber.newValue = value;
  626.     err = CallBackDET(callBlockPtr, &callBack);
  627.     
  628.     if (err==noErr)
  629.         err = DirtyProperty(callBlockPtr, property);
  630.     
  631.     return err;
  632. }
  633.  
  634.  
  635. // GetNumProperty
  636. //
  637. // gets a number property value out of a template and returns it to us
  638. //
  639. OSErr GetNumProperty(DETCallBlockPtr callBlockPtr, short property, long *value)
  640. {
  641.     OSErr err;
  642.     DETCallBackBlock callBack;
  643.     
  644.     callBack.getPropertyNumber.reqFunction = kDETcmdGetPropertyNumber;
  645.     callBack.getPropertyNumber.property = property;
  646.     callBack.getPropertyNumber.target.selector = kDETSelf;
  647.     err = CallBackDET(callBlockPtr, &callBack);
  648.     
  649.     *value = callBack.getPropertyNumber.propertyValue;
  650.     
  651.     return err;
  652. }
  653.  
  654.  
  655. // DirtyProperty
  656. //
  657. // tells the DE that we've changed a property and that it should mark it for update
  658. //
  659. OSErr DirtyProperty(DETCallBlockPtr callBlockPtr, short property)
  660. {
  661.     OSErr err;
  662.     DETCallBackBlock callBack;
  663.  
  664.     callBack.dirtyProperty.reqFunction = kDETcmdDirtyProperty;
  665.     callBack.dirtyProperty.property = property;
  666.     callBack.dirtyProperty.target.selector = kDETSelf;
  667.  
  668.     err = CallBackDET(callBlockPtr, &callBack);
  669.     
  670.     return err;
  671. }
  672.  
  673.  
  674. // GetFileID
  675. //
  676. // uses the DE callback mechanism to get the FSSpec for the template file and
  677. // then changes this value into a file id via PBCreateFileIDRef
  678. //
  679. OSErr GetFileID(DETCallBlockPtr callBlockPtr,long *fileID)
  680. {
  681.     DETCallBackBlock callBack;
  682.     OSErr err;
  683.     FIDParam fidBlock;
  684.         
  685.     callBack.getTemplateFSSpec.reqFunction = kDETcmdGetTemplateFSSpec;
  686.     callBack.getTemplateFSSpec.target.selector = kDETSelf;
  687.     err = CallBackDET(callBlockPtr, &callBack);
  688.     if (err==noErr) {
  689.         fidBlock.ioVRefNum = callBack.getTemplateFSSpec.fsSpec.vRefNum;
  690.         fidBlock.ioSrcDirID = callBack.getTemplateFSSpec.fsSpec.parID;
  691.         fidBlock.ioNamePtr = callBack.getTemplateFSSpec.fsSpec.name;
  692.         err = PBCreateFileIDRef((HParmBlkPtr)&fidBlock,false);
  693.         *fileID = fidBlock.ioFileID;
  694.         if (err==fidExists)
  695.             err = noErr;
  696.     }
  697.     
  698.     return err;
  699. }
  700.  
  701.  
  702. // DoBusy
  703. //
  704. // tells DE that we want to give some time to other applications for a short while
  705. // (probably will call WaitNextEvent for us
  706. //
  707. OSErr DoBusy(DETCallBlockPtr callBlockPtr)
  708. {
  709.     DETCallBackBlock callBack;
  710.         
  711.     callBack.busy.reqFunction = kDETcmdBusy;
  712.     return (CallBackDET(callBlockPtr, &callBack));
  713. }
  714.  
  715.  
  716. // RequestSync
  717. //
  718. // tells the DE that it should make sure all of the DE Templates are in sync with their values
  719. //
  720. OSErr RequestSync(DETCallBlockPtr callBlockPtr)
  721. {
  722.     DETCallBackBlock callBack;
  723.     
  724.     callBack.requestSync.reqFunction = kDETcmdRequestSync;
  725.     callBack.requestSync.target.selector = kDETSelf;
  726.     return CallBackDET(callBlockPtr, &callBack);
  727. }
  728.  
  729.  
  730.  
  731. //---------------------------------------------------------------------------------------
  732. //---------------------------------------------------------------------------------------
  733.  
  734.  
  735. OSErr ModifyOurSlot(DETCallBlockPtr callBlockPtr,GlobalData *globalData)
  736. {
  737.     OSErr err;
  738.     CreationID msamCID;
  739.     MailModifyMailSlotPB modifySlot;
  740.     
  741.     // get reference to MSAM record
  742.     
  743.     err = GetSingleRecord(globalData->oceSetupDSRef,OCEGetIndRecordType(kMSAMRecTypeNum),kMSAMRecordName,&msamCID);
  744.     if (err!=noErr)
  745.         return err;
  746.         
  747.     // change user's external identity in directory record
  748.     
  749.     err = ChangeDirectoryIdentity(&globalData->directoryCID,globalData->config.dirIdentity.userName,
  750.                 globalData->config.dirIdentity.password,globalData->config.dirIdentity.oldPassword);
  751.     if (err!=noErr)
  752.         return err;
  753.     strcpy(globalData->config.dirIdentity.oldPassword,globalData->config.dirIdentity.password);
  754.         
  755.     // change StdSlotInfo attribute in mailservice record
  756.     
  757.     err = ChangeSingleAttribute(&globalData->mailCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kStdSlotInfoAttrTypeNum),
  758.                     &globalData->config.stdInfo,sizeof(MailStandardSlotInfoAttribute),typeBinary);
  759.     if (err!=noErr)
  760.         return err;
  761.  
  762.     // add SpecificSlotInfo to mailservice record
  763.     
  764.     err = ChangeSingleAttribute(&globalData->mailCID,globalData->oceSetupDSRef,kSetupAttr,
  765.                     &globalData->config.specInfo,sizeof(SpecificSlotInfo),typeBinary);
  766.     if (err!=noErr)
  767.         return err;
  768.             
  769.     // call MailModifySlot
  770.     
  771.     modifySlot.mailboxRef = 0;
  772.     modifySlot.timeout = kTimeout;
  773.     OCECopyCreationID(&msamCID,&modifySlot.pmsamCID);
  774.     modifySlot.smca.smcaLength = sizeof(SMCA);
  775.     modifySlot.smca.result = 1;    // call is running
  776.     modifySlot.smca.userBytes = 0;
  777.     modifySlot.ioCompletion = nil;
  778.     OCECopyCreationID(&globalData->mailCID,&modifySlot.smca.u.slotCID); 
  779.         
  780.     err = MailModifyMailSlot((MSAMParam *)&modifySlot);
  781.     if (err!=noErr)
  782.         return err;
  783.     
  784.     // wait for MailModifyMailSlot to complete
  785.     
  786.     while (modifySlot.ioResult==1) {
  787.         err = DoBusy(callBlockPtr);
  788.         if (err!=noErr)
  789.             return err;
  790.     }
  791.     
  792.     err = RequestSync(callBlockPtr);
  793.     if (err!=noErr)
  794.         return err;
  795.         
  796.     return noErr;
  797. }
  798.  
  799.  
  800. OSErr CreateOurSlot(DETCallBlockPtr callBlockPtr,GlobalData *globalData)
  801. {
  802.     OSErr err;
  803.     RString rstr;
  804.     CreationID msamCID,ocesCID,attrCID;
  805.     long version;
  806.     long fileID,oldFileID;
  807.     RecordID msRecordUnpacked;
  808.     PackedRecordID msRecord;
  809.     MailCreateMailSlotPB createMailSlot;
  810.     DirDiscriminator discriminator = {kDirectoryOSType,0};
  811.     RecordID dirRecordUnpacked;
  812.     PackedRecordID dirRecord;
  813.     
  814.     // if directory is fake, check to see if we need to add the native name,etc...
  815.     
  816.     if (globalData->fakeDirectory) {
  817.             
  818.         err = GetSingleValueAttribute(&globalData->directoryCID,globalData->oceSetupDSRef,
  819.                 OCEGetIndAttributeType(kDirNativeNameAttrTypeNum),&rstr,sizeof(RString),&attrCID);
  820.         if (err!=noErr) { // native name attribute not present yet
  821.  
  822.             // add native name
  823.             
  824.             OCECToRString(globalData->config.dirIdentity.userName,smRoman,&rstr,kRStringMaxChars);
  825.             err = AddAttribute(&globalData->directoryCID,globalData->oceSetupDSRef,
  826.                         OCEGetIndAttributeType(kDirNativeNameAttrTypeNum),&rstr,rstr.dataLength+4,typeRString);
  827.             if (err!=noErr)
  828.                 return err;
  829.  
  830.             // add comment
  831.             
  832.             err = AddAttribute(&globalData->directoryCID,globalData->oceSetupDSRef,
  833.                         OCEGetIndAttributeType(kCommentAttrTypeNum),kDirectoryComment,kCommentLength,typeRString);
  834.             if (err!=noErr)
  835.                 return err;
  836.  
  837.             // add real name
  838.             
  839.             err = AddAttribute(&globalData->directoryCID,globalData->oceSetupDSRef,
  840.                         OCEGetIndAttributeType(kRealNameAttrTypeNum),kDirectoryName,kDirNameLength,typeRString);
  841.             if (err!=noErr)
  842.                 return err;
  843.             
  844.             // set name of directory to a unique name (we only have 1 slot, so we sort of hardcode this)
  845.             
  846.             err = SetRecNameAndType(&globalData->directoryCID,globalData->oceSetupDSRef,(RStringPtr)kDirectoryName,kDirectoryType);
  847.             if (err!=noErr)
  848.                 return err;
  849.             
  850.             // add OCESetupDirectoryInfo
  851.             
  852.             err = AddDirectoryIdentity(&globalData->directoryCID,globalData->config.dirIdentity.userName,
  853.                         globalData->config.dirIdentity.password);
  854.             if (err!=noErr)
  855.                 return err;
  856.             strcpy(globalData->config.dirIdentity.oldPassword,globalData->config.dirIdentity.password);
  857.                         
  858.             // add discriminator attribute (not needed according to setup document)
  859.             
  860.             err = AddAttribute(&globalData->directoryCID,globalData->oceSetupDSRef,
  861.                         OCEGetIndAttributeType(kDiscriminatorAttrTypeNum),&discriminator,sizeof(DirDiscriminator),typeBinary);
  862.             if (err!=noErr)
  863.                 return err;
  864.             
  865.             // get reference to master OCE Setup Record
  866.             
  867.             err = GetSingleRecord(globalData->oceSetupDSRef,OCEGetIndRecordType(kSetupRecTypeNum),kOCESetupRecName,&ocesCID);
  868.             if (err!=noErr)
  869.                 return err;
  870.             
  871.             // add our fake directory to the Directories attribute type
  872.             
  873.             MakePersonalRecordID(&dirRecordUnpacked,&globalData->directoryCID);
  874.             err = OCEPackRecordID(&dirRecordUnpacked,&dirRecord,kPackedRecordIDMaxBytes);
  875.             if (err!=noErr)
  876.                 return err;
  877.             err = AddAttribute(&ocesCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kDirectoriesAttrTypeNum),
  878.                         &dirRecord,dirRecord.dataLength+sizeof(short),typeBinary);
  879.             if (err!=noErr)
  880.                 return err;            
  881.             
  882.  
  883.         }
  884.         else {
  885.  
  886.             // change OCESetupDirectoryInfo
  887.             
  888.             err = ChangeDirectoryIdentity(&globalData->directoryCID,globalData->config.dirIdentity.userName,
  889.                         globalData->config.dirIdentity.password,globalData->config.dirIdentity.oldPassword);
  890.             strcpy(globalData->config.dirIdentity.oldPassword,globalData->config.dirIdentity.password);
  891.         }
  892.  
  893.     }
  894.     
  895.     err = GetSingleRecord(globalData->oceSetupDSRef,OCEGetIndRecordType(kMSAMRecTypeNum),kMSAMRecordName,&msamCID);
  896.     if (err!=noErr) {
  897.     
  898.         // make MSAM record
  899.         
  900.         err = AddRecord(globalData->oceSetupDSRef,kMSAMRecordName,OCEGetIndRecordType(kMSAMRecTypeNum),&msamCID);
  901.         if (err!=noErr)
  902.             return err;
  903.         
  904.         // add version
  905.         
  906.         version = kMSAMVersion;
  907.         err = AddAttribute(&msamCID,globalData->oceSetupDSRef,kVersionAttribute,&version,sizeof(long),typeBinary);
  908.         if (err!=noErr)
  909.             return err;
  910.         
  911.         // add file id
  912.  
  913.         err = GetFileID(callBlockPtr,&fileID);
  914.         if (err!=noErr)
  915.             return err;
  916.         err = AddAttribute(&msamCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kGatewayFileIDAttrTypeNum),
  917.                         &fileID,sizeof(long),typeBinary);
  918.         if (err!=noErr)
  919.             return err;
  920.     }
  921.     else {
  922.     
  923.         // make sure that the file ID attribute is still valid.  If not, replace it, since the user may have upgraded
  924.         // from an older version of the MSAM.
  925.         
  926.         err = GetFileID(callBlockPtr,&fileID);
  927.         if (err!=noErr)
  928.             return err;
  929.         GetSingleValueAttribute(&msamCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kGatewayFileIDAttrTypeNum),
  930.                         &oldFileID,sizeof(long),&attrCID);
  931.         if (err!=noErr)
  932.             return err;
  933.         if (oldFileID!=fileID) {
  934.             err = ChangeSingleAttribute(&msamCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kGatewayFileIDAttrTypeNum),
  935.                     &fileID,sizeof(long),typeBinary);
  936.             if (err!=noErr)
  937.                 return err;
  938.         }
  939.  
  940.     }
  941.  
  942.     // add ParentMSAM attribute to mailservice record
  943.     
  944.     MakePersonalRecordID(&msRecordUnpacked,&msamCID);
  945.     err = OCEPackRecordID(&msRecordUnpacked,&msRecord,kPackedRecordIDMaxBytes);
  946.     if (err!=noErr)
  947.         return err;
  948.     err = AddAttribute(&globalData->mailCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kParentMSAMAttrTypeNum),
  949.                         &msRecord,msRecord.dataLength+sizeof(short),typeBinary);
  950.     if (err!=noErr)
  951.         return err;
  952.     
  953.     // add StdSlotInfo attribute to mailservice record
  954.     
  955.     err = AddAttribute(&globalData->mailCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kStdSlotInfoAttrTypeNum),
  956.                     &globalData->config.stdInfo,sizeof(MailStandardSlotInfoAttribute),typeBinary);
  957.     if (err!=noErr)
  958.         return err;
  959.  
  960.     // add SpecificSlotInfo to mailservice record
  961.     
  962.     err = AddAttribute(&globalData->mailCID,globalData->oceSetupDSRef,kSetupAttr,
  963.                     &globalData->config.specInfo,sizeof(SpecificSlotInfo),typeBinary);
  964.     if (err!=noErr)
  965.         return err;
  966.         
  967.     // call MailCreateMailSlot  
  968.  
  969.     createMailSlot.mailboxRef = 0;
  970.     createMailSlot.timeout = kTimeout;
  971.     OCECopyCreationID(&msamCID,&createMailSlot.pmsamCID);
  972.     createMailSlot.smca.smcaLength = sizeof(SMCA);
  973.     createMailSlot.smca.result = 1;    // call is running
  974.     createMailSlot.smca.userBytes = 0;
  975.     createMailSlot.ioCompletion = nil;
  976.     OCECopyCreationID(&globalData->mailCID,&createMailSlot.smca.u.slotCID); 
  977.         
  978.     err = MailCreateMailSlot((MSAMParam *)&createMailSlot);
  979.     if (err!=noErr)
  980.         return err;
  981.     
  982.     // wait for MailCreateMailSlot to complete
  983.     
  984.     while (createMailSlot.ioResult==1) {
  985.         err = DoBusy(callBlockPtr);
  986.         if (err!=noErr)
  987.             return err;
  988.     }
  989.  
  990.     // add new mailservices attribute to MSAM record since we were added successfully
  991.     
  992.     MakePersonalRecordID(&msRecordUnpacked,&globalData->mailCID);
  993.     err = OCEPackRecordID(&msRecordUnpacked,&msRecord,kPackedRecordIDMaxBytes);
  994.     if (err!=noErr)
  995.         return err;
  996.     err = AddAttribute(&msamCID,globalData->oceSetupDSRef,OCEGetIndAttributeType(kMailServiceAttrTypeNum),
  997.                         &msRecord,msRecord.dataLength+sizeof(short),typeBinary);
  998.     if (err!=noErr)
  999.         return err;
  1000.     
  1001.     return err;
  1002. }
  1003.  
  1004.  
  1005. //---------------------------------------------------------------------------------------
  1006. //---------------------------------------------------------------------------------------
  1007.  
  1008.  
  1009. // ChangeSingleAttribute
  1010. //
  1011. // changes the value of a single attribute to the new value passed in.  this only works correctly if the attribute
  1012. // type is single-valued
  1013. //
  1014. OSErr ChangeSingleAttribute(const CreationID *cid,short dsRef,AttributeType *attribType,void *data,unsigned long dataLength,AttributeTag tag)
  1015. {
  1016.     OSErr err;
  1017.     CreationID oldCID;
  1018.     char *blank;
  1019.     Attribute oldAttribute,newAttribute;
  1020.     RecordID attrRecordID;
  1021.     DirParamBlock attrBlock;
  1022.     
  1023.     // set up aRecord parameter
  1024.     
  1025.     MakePersonalRecordID(&attrRecordID,cid);
  1026.  
  1027.     // set up currentAttr parameter
  1028.     
  1029.     err = GetSingleValueAttribute(cid,dsRef,attribType,nil,0L,&oldCID);
  1030.     if (err!=noErr)
  1031.         return err;    // no previous record
  1032.     for (blank=(char*)&oldAttribute;(blank-(char*)&oldAttribute)<sizeof(Attribute);blank++)
  1033.         *blank=0;
  1034.     OCECopyCreationID(&oldCID,&oldAttribute.cid);
  1035.     
  1036.     // set up newAttr parameter
  1037.     
  1038.     for (blank=(char*)&newAttribute;(blank-(char*)&newAttribute)<sizeof(Attribute);blank++)
  1039.         *blank=0;
  1040.     OCECopyRString((const RString *)attribType, (RString *)&newAttribute.attributeType,kAttributeTypeMaxBytes);
  1041.     newAttribute.value.tag = tag;
  1042.     newAttribute.value.dataLength = dataLength;
  1043.     newAttribute.value.bytes = (Ptr)data;
  1044.     
  1045.     attrBlock.changeAttributeValuePB.serverHint.aNet = 0;
  1046.     attrBlock.changeAttributeValuePB.serverHint.aNode = 0;
  1047.     attrBlock.changeAttributeValuePB.serverHint.aSocket = 0;
  1048.     attrBlock.changeAttributeValuePB.dsRefNum = dsRef;
  1049.     attrBlock.changeAttributeValuePB.identity = kIdentity;
  1050.     attrBlock.changeAttributeValuePB.aRecord = &attrRecordID;
  1051.     attrBlock.changeAttributeValuePB.currentAttr = &oldAttribute;
  1052.     attrBlock.changeAttributeValuePB.newAttr = &newAttribute;
  1053.     err = DirChangeAttributeValue(&attrBlock,false);
  1054.     return err;
  1055. }
  1056.  
  1057.  
  1058. // DeleteAttributeType
  1059. //
  1060. // deletes the attribute type passed in and all associated
  1061. // values to that type
  1062. //
  1063. OSErr DeleteAttributeType(const CreationID *cid,short dsRef,AttributeType *attribType)
  1064. {
  1065.     OSErr err;
  1066.     RecordID attrRecordID;
  1067.     char *blank;
  1068.     DirParamBlock dirBlock;
  1069.         
  1070.     MakePersonalRecordID(&attrRecordID,cid);
  1071.     
  1072.     for (blank=(char*)&dirBlock;(blank-(char*)&dirBlock)<sizeof(DirParamBlock);blank++)
  1073.         *blank=0;
  1074.  
  1075.     dirBlock.deleteAttributeTypePB.serverHint.aNet = 0;
  1076.     dirBlock.deleteAttributeTypePB.serverHint.aNode = 0;
  1077.     dirBlock.deleteAttributeTypePB.serverHint.aSocket = 0;
  1078.     dirBlock.deleteAttributeTypePB.dsRefNum = dsRef;
  1079.     dirBlock.deleteAttributeTypePB.identity = kIdentity;
  1080.     dirBlock.deleteAttributeTypePB.aRecord = &attrRecordID;
  1081.     dirBlock.deleteAttributeTypePB.attrType = attribType;
  1082.     err = DirDeleteAttributeValue(&dirBlock,false);
  1083.     return err;
  1084. }
  1085.  
  1086.  
  1087. // GetSingleValueAttribute
  1088. //
  1089. // this routine returns a single attribute value from a record.  it's used to get information out
  1090. // of the slot setup information
  1091. //
  1092. OSErr GetSingleValueAttribute(const CreationID *cid,short dsRef,AttributeType *attribType,void *attrBuffer,Size attrBufferSize,CreationID *retCID)
  1093. {
  1094.     DirParamBlock dirBlock;
  1095.     Ptr buff;
  1096.     OSErr err;
  1097.     RecordIDPtr recordList[1];
  1098.     AttributeTypePtr attrList[1];
  1099.     RecordID recordID;
  1100.     char *blank;
  1101.     AttributeCopyInfo callbackInfo;
  1102.     
  1103.     callbackInfo.buffer = attrBuffer;
  1104.     callbackInfo.bufferSize = attrBufferSize;
  1105.     callbackInfo.creationID = retCID;
  1106.     callbackInfo.gotOne = false;
  1107.     
  1108.     MakePersonalRecordID(&recordID,cid);
  1109.     
  1110.     recordList[0] = (RecordIDPtr)&recordID;
  1111.     attrList[0] = attribType;
  1112.     buff = NewPtr(kAttrBufferSize);
  1113.     if (MemError()!=noErr)
  1114.         return MemError();
  1115.     
  1116.     for (blank=(char*)&dirBlock;(blank-(char*)&dirBlock)<sizeof(DirParamBlock);blank++)
  1117.         *blank=0;
  1118.         
  1119.     dirBlock.header.ioCompletion = nil;
  1120.     dirBlock.header.clientData = (long)&callbackInfo;
  1121.     dirBlock.lookupGetPB.serverHint.aNet = 0;
  1122.     dirBlock.lookupGetPB.serverHint.aNode = 0;
  1123.     dirBlock.lookupGetPB.serverHint.aSocket = 0;
  1124.     dirBlock.lookupGetPB.dsRefNum = dsRef;
  1125.     dirBlock.lookupGetPB.identity = kIdentity;
  1126.     dirBlock.lookupGetPB.aRecordList = recordList;
  1127.     dirBlock.lookupGetPB.attrTypeList = attrList;
  1128.     dirBlock.lookupGetPB.recordIDCount = 1;
  1129.     dirBlock.lookupGetPB.attrTypeCount = 1;
  1130.     dirBlock.lookupGetPB.includeStartingPoint = false;
  1131.     dirBlock.lookupGetPB.getBuffer = buff;
  1132.     dirBlock.lookupGetPB.getBufferSize = kAttrBufferSize;
  1133.     dirBlock.lookupGetPB.startingRecordIndex = 1;
  1134.     dirBlock.lookupGetPB.startingAttrTypeIndex = 1;
  1135.     dirBlock.lookupParsePB.eachRecordID = RecordIDCallback;
  1136.     dirBlock.lookupParsePB.eachAttrType = nil;
  1137.     dirBlock.lookupParsePB.eachAttrValue = SingleAttrValueCallback;
  1138.     OCESetCreationIDtoNull(&dirBlock.lookupGetPB.startingAttribute.cid);
  1139.     
  1140.     err = DirLookupGet(&dirBlock,false);
  1141.     if (err==noErr || err==kOCEMoreData)
  1142.         err = DirLookupParse(&dirBlock,false);
  1143.     
  1144.     if ((err==noErr) && !callbackInfo.gotOne)
  1145.         err = kNoRecords;
  1146.         
  1147.     DisposPtr(buff);
  1148.     return err;
  1149. }
  1150.  
  1151.  
  1152. pascal Boolean RecordIDCallback(long clientData, const RecordID *recordID)
  1153. {
  1154.     #pragma unused (clientData,recordID)
  1155.     return false;
  1156. }
  1157.  
  1158.  
  1159. pascal Boolean SingleAttrValueCallback(long clientData, const Attribute *attribute)
  1160. {
  1161.     AttributeCopyInfoPtr callbackInfo;
  1162.     Size moveSize;
  1163.     
  1164.     callbackInfo = (AttributeCopyInfoPtr) clientData;
  1165.         
  1166.     if (callbackInfo->bufferSize>0) {
  1167.         moveSize = attribute->value.dataLength;
  1168.         if (moveSize>callbackInfo->bufferSize)
  1169.             moveSize = callbackInfo->bufferSize;
  1170.         BlockMove(attribute->value.bytes,callbackInfo->buffer,moveSize);
  1171.     }
  1172.     
  1173.     OCECopyCreationID(&attribute->cid,callbackInfo->creationID);
  1174.     callbackInfo->gotOne = true;
  1175.     
  1176.     return false;
  1177. }
  1178.  
  1179.  
  1180. // GetSingleRecord
  1181. //
  1182. // returns the RecordID for a record of a given type, if it matches the name you were
  1183. // looking for which is passed in
  1184. //
  1185. OSErr GetSingleRecord(short dsRef,RStringPtr recordType,RStringPtr recordName,CreationID *returnedCID)
  1186. {
  1187.     DirParamBlock dirBlock;
  1188.     Ptr buff;
  1189.     char *blank;
  1190.     RStringPtr typesList[1];
  1191.     OSErr err;
  1192.     RecordCopyInfo recCopyInfo;
  1193.     
  1194.     buff = NewPtr(kRecordBufferSize);
  1195.     if (MemError()!=noErr)
  1196.         return MemError();
  1197.  
  1198.     for (blank=(char*)&dirBlock;(blank-(char*)&dirBlock)<sizeof(DirParamBlock);blank++)
  1199.         *blank=0;
  1200.     
  1201.     typesList[0] = recordType;
  1202.     
  1203.     recCopyInfo.gotOne = false;
  1204.     recCopyInfo.creationID = returnedCID;
  1205.     recCopyInfo.recordName = recordName;
  1206.     
  1207.     dirBlock.enumerateGetPB.serverHint.aNet = 0;
  1208.     dirBlock.enumerateGetPB.serverHint.aNode = 0;
  1209.     dirBlock.enumerateGetPB.serverHint.aSocket = 0;
  1210.     dirBlock.enumerateGetPB.dsRefNum = dsRef;
  1211.     dirBlock.enumerateGetPB.identity = kIdentity;
  1212.     dirBlock.enumerateGetPB.clientData = (long)&recCopyInfo;
  1213.     dirBlock.enumerateGetPB.aRLI = nil;
  1214.     dirBlock.enumerateGetPB.startingPoint = nil;
  1215.     dirBlock.enumerateGetPB.sortBy = kSortByName;
  1216.     dirBlock.enumerateGetPB.sortDirection = kSortForwards;
  1217.     dirBlock.enumerateGetPB.typesList = typesList;
  1218.     dirBlock.enumerateGetPB.typeCount = 1;
  1219.     dirBlock.enumerateGetPB.enumFlags = kEnumDistinguishedNameMask;
  1220.     dirBlock.enumerateGetPB.includeStartingPoint = false;
  1221.     dirBlock.enumerateGetPB.getBuffer = buff;
  1222.     dirBlock.enumerateGetPB.getBufferSize = kRecordBufferSize;
  1223.     dirBlock.enumerateParsePB.eachEnumSpec = GatewayDirEnumCallback;
  1224.     
  1225.     err = DirEnumerateGet(&dirBlock,false);
  1226.     if (err==noErr || err==kOCEMoreData)
  1227.         err = DirEnumerateParse(&dirBlock,false);
  1228.  
  1229.     DisposPtr(buff);
  1230.     
  1231.     if ((err==noErr) && !recCopyInfo.gotOne)
  1232.         err = kNoRecords;
  1233.         
  1234.     return err;
  1235. }
  1236.  
  1237.  
  1238. pascal Boolean GatewayDirEnumCallback(long clientData, const DirEnumSpec *enumSpec)
  1239. {
  1240.     RecordCopyInfo *recCopyInfo;
  1241.     
  1242.     recCopyInfo = (RecordCopyInfo *)clientData;
  1243.     
  1244.     if (!recCopyInfo->gotOne && enumSpec->enumFlag & kEnumDistinguishedNameMask &&
  1245.         OCEEqualRString(recCopyInfo->recordName,enumSpec->u.recordIdentifier.recordName,kOCERecordOrDNodeName)) {
  1246.  
  1247.         OCECopyCreationID(&enumSpec->u.recordIdentifier.cid,recCopyInfo->creationID);
  1248.         recCopyInfo->gotOne = true;
  1249.         return true;
  1250.         
  1251.     }
  1252.     return false;
  1253. }
  1254.  
  1255.  
  1256. // AddAttribute
  1257. //
  1258. // add an attribute value to a record
  1259. //
  1260. OSErr AddAttribute(const CreationID *cid,short dsRef,AttributeType *attribType,void *data,unsigned long dataLength,AttributeTag tag)
  1261. {
  1262.     DirParamBlock attrBlock;
  1263.     RecordID recordID;
  1264.     Attribute attribute;
  1265.     OSErr err;
  1266.     char *blank;
  1267.     
  1268.     MakePersonalRecordID(&recordID,cid);
  1269.     
  1270.     attrBlock.addAttributeValuePB.serverHint.aNet = 0;
  1271.     attrBlock.addAttributeValuePB.serverHint.aNode = 0;
  1272.     attrBlock.addAttributeValuePB.serverHint.aSocket = 0;
  1273.     attrBlock.addAttributeValuePB.dsRefNum = dsRef;
  1274.     attrBlock.addAttributeValuePB.identity = kIdentity;
  1275.     attrBlock.addAttributeValuePB.aRecord = &recordID;
  1276.     attrBlock.addAttributeValuePB.attr = &attribute;
  1277.  
  1278.     for (blank=(char*)&attribute;(blank-(char*)&attribute)<sizeof(Attribute);blank++)
  1279.         *blank=0;
  1280.     OCECopyRString((const RString *)attribType, (RString *)&attribute.attributeType,kAttributeTypeMaxBytes);
  1281.     attribute.value.tag = tag;
  1282.     attribute.value.dataLength = dataLength;
  1283.     attribute.value.bytes = (Ptr)data;
  1284.     err = DirAddAttributeValue(&attrBlock,false);
  1285.  
  1286.     return err;
  1287. }
  1288.  
  1289.  
  1290. // SetRecNameAndType
  1291. //
  1292. // sets the name and type of the record pointed to by the CID passed in
  1293. //
  1294. OSErr SetRecNameAndType(const CreationID *cid,short dsRef,RStringPtr newName,RStringPtr newType)
  1295. {
  1296.     DirSetNameAndTypePB dirBlock;
  1297.     RecordID recordID;
  1298.     OSErr err;
  1299.     
  1300.     MakePersonalRecordID(&recordID,cid);
  1301.     
  1302.     dirBlock.serverHint.aNet = 0;
  1303.     dirBlock.serverHint.aNode = 0;
  1304.     dirBlock.serverHint.aSocket = 0;
  1305.     dirBlock.dsRefNum = dsRef;
  1306.     dirBlock.identity = kIdentity;
  1307.     dirBlock.aRecord = &recordID;
  1308.     dirBlock.allowDuplicate = false;    // don't allow duplicate name/type
  1309.     dirBlock.newName = newName;
  1310.     dirBlock.newType = newType;
  1311.     err = DirSetNameAndType((DirParamBlockPtr)&dirBlock,false);
  1312.     
  1313.     return err;
  1314. }
  1315.  
  1316.  
  1317. // AddRecord
  1318. //
  1319. // adds a record into a personal directory and returns its CID
  1320. //
  1321. OSErr AddRecord(short dsRefNum,RStringPtr recordName,RStringPtr recordType,CreationID *newCID)
  1322. {
  1323.     DirAddRecordPB addRecordPB;
  1324.     OSErr err;
  1325.     RecordID recordID;
  1326.     
  1327.     addRecordPB.serverHint.aNet = 0;
  1328.     addRecordPB.serverHint.aNode = 0;
  1329.     addRecordPB.serverHint.aSocket = 0;
  1330.     addRecordPB.dsRefNum = dsRefNum;
  1331.     addRecordPB.identity = kIdentity;
  1332.     addRecordPB.allowDuplicate = false;
  1333.     addRecordPB.aRecord = &recordID;
  1334.     recordID.local.recordName = recordName;
  1335.     recordID.local.recordType = recordType;
  1336.     recordID.rli = nil;
  1337.     OCESetCreationIDtoNull(&recordID.local.cid);
  1338.     err = DirAddRecord((DirParamBlock*)&addRecordPB,false);
  1339.     if (err==noErr)
  1340.         OCECopyCreationID(&recordID.local.cid,newCID);
  1341.         
  1342.     return err;
  1343. }
  1344.  
  1345.  
  1346. // AddDirectoryIdentity
  1347. //
  1348. // add a name and password identity to a directory record
  1349. //
  1350. OSErr AddDirectoryIdentity(const CreationID *cid,char *userName,char *password)
  1351. {
  1352.     OCESetupAddDirectoryInfoPB authBlock;
  1353.     OSErr err;
  1354.     RString rsUserName,rsPassword;
  1355.     DirDiscriminator discriminator = {kDirectoryOSType, 0};
  1356.     DNodeNum dNodeNumber = 0;
  1357.     PackedRLI pRLI;
  1358.     RecordID userRID;
  1359.     
  1360.     OCECToRString(userName, smRoman, &rsUserName, kRStringMaxChars);
  1361.     OCECToRString(password, smRoman, &rsPassword, kRStringMaxChars);
  1362.     OCEPackRLIParts(kDirectoryName, &discriminator, dNodeNumber, nil, 0, &pRLI, kPackedRecordIDMaxBytes);
  1363.     userRID.rli = &pRLI;
  1364.     userRID.local.recordName = &rsUserName;
  1365.     userRID.local.recordType = OCEGetIndRecordType(kUserRecTypeNum);
  1366.     OCECopyCreationID(cid,&authBlock.directoryRecordCID);
  1367.     authBlock.recordID = &userRID;
  1368.     authBlock.password = &rsPassword;
  1369.     err = OCESetupAddDirectoryInfo((AuthParamBlockPtr)&authBlock,false);
  1370.     
  1371.     return err;
  1372. }
  1373.  
  1374.  
  1375. // ChangeDirectoryIdentity
  1376. //
  1377. // change an existing directory identity
  1378. //
  1379. OSErr ChangeDirectoryIdentity(const CreationID *cid,char *userName,char *password,char *oldPassword)
  1380. {
  1381.     OCESetupChangeDirectoryInfoPB authBlock;
  1382.     OSErr err;
  1383.     RString rsUserName,rsPassword,rsOldPassword;
  1384.     DirDiscriminator discriminator = {kDirectoryOSType, 0};
  1385.     DNodeNum dNodeNumber = 0;
  1386.     PackedRLI pRLI;
  1387.     RecordID userRID;
  1388.     
  1389.     OCECToRString(userName, smRoman, &rsUserName, kRStringMaxChars);
  1390.     OCECToRString(password, smRoman, &rsPassword, kRStringMaxChars);
  1391.     OCECToRString(oldPassword, smRoman, &rsOldPassword, kRStringMaxChars);
  1392.     OCEPackRLIParts(kDirectoryName, &discriminator, dNodeNumber, nil, 0, &pRLI, kPackedRecordIDMaxBytes);
  1393.     userRID.rli = &pRLI;
  1394.     userRID.local.recordName = &rsUserName;
  1395.     userRID.local.recordType = OCEGetIndRecordType(kUserRecTypeNum);
  1396.     OCECopyCreationID(cid,&authBlock.directoryRecordCID);
  1397.     authBlock.recordID = &userRID;
  1398.     authBlock.password = &rsOldPassword;
  1399.     authBlock.newPassword = &rsPassword;
  1400.     err = OCESetupChangeDirectoryInfo((AuthParamBlockPtr)&authBlock,false);
  1401.     
  1402.     return err;
  1403. }
  1404.  
  1405.  
  1406. // MakePersonalRecordID
  1407. //
  1408. // this convenience function fills in a RecordID given a creation ID, since a fully specified
  1409. // record ID for a personal directory contains only a creation ID
  1410. //
  1411. void MakePersonalRecordID(RecordID *recordID,const CreationID *creationID)
  1412. {
  1413.     recordID->rli = nil;
  1414.     OCECopyCreationID(creationID,&recordID->local.cid);
  1415.     recordID->local.recordName = nil;
  1416.     recordID->local.recordType = nil;
  1417. }
  1418.  
  1419.  
  1420. // GetCreationIDFromDSSpec
  1421. //
  1422. // pulls the CreationID out of a PackedDSSpec
  1423. //
  1424. void GetCreationIDFromDSSpec(const PackedDSSpec *dsSpec,CreationID *cid)
  1425. {
  1426.     DSSpec unpackedDSSpec;
  1427.     RecordID recordID;
  1428.     
  1429.     OCEUnpackDSSpec(dsSpec,&unpackedDSSpec,&recordID);
  1430.     OCECopyCreationID(&recordID.local.cid,cid);
  1431. }
  1432.  
  1433.  
  1434. //---------------------------------------------------------------------------------------
  1435. //---------------------------------------------------------------------------------------
  1436.  
  1437. OSErr SetUserPassword(char *passwordStorage)
  1438. {
  1439.     short saveResFile,myResFile;
  1440.     Handle codeHndl;
  1441.     
  1442.     // set our resource file to the current resource file
  1443.     
  1444.     saveResFile = CurResFile();
  1445.     codeHndl = RecoverHandle((Ptr)MailServiceCode);
  1446.     if (!codeHndl)
  1447.         return kInternalError;
  1448.     myResFile = HomeResFile(codeHndl);
  1449.     if (myResFile==0 || myResFile==1 || myResFile==-1)
  1450.         return kInternalError;
  1451.     UseResFile(myResFile);
  1452.     
  1453.     // let the user change the password (given the old one)
  1454.     
  1455.     ChangePassword(passwordStorage);
  1456.     
  1457.     // restore the old resource file
  1458.     UseResFile(saveResFile);
  1459.     
  1460.     return noErr;
  1461. }
  1462.  
  1463.  
  1464. void ChangePassword(char *pwStorage)
  1465. {
  1466.     char oldPassword[64],newPassword[64];
  1467.     
  1468.     if (!GetPasswordDialog(oldPassword,newPassword,pwStorage[0]!=0))
  1469.         return;    // user cancelled
  1470.     
  1471.     if (strcmp(oldPassword,pwStorage)!=0) {
  1472.         StopAlert(kIncorrectPWAlert,nil);
  1473.         return;
  1474.     }
  1475.     
  1476.     strcpy(pwStorage,newPassword);
  1477. }
  1478.  
  1479.  
  1480. Boolean GetPasswordDialog(char *oldPassword,char *password,Boolean hasPassword)
  1481. {
  1482.     short item;
  1483.     DialogPtr theDialog;
  1484.     PasswordDialogData theData;
  1485.     
  1486.     oldPassword[0] = 0;
  1487.     password[0] = 0;
  1488.     theData.oldPassword = oldPassword;
  1489.     theData.password = password;
  1490.  
  1491.     if (hasPassword)
  1492.         theDialog = GetNewDialog(kPasswordDialog,nil,(WindowPtr)-1L);
  1493.     else
  1494.         theDialog = GetNewDialog(kNoPrevPassDialog,nil,(WindowPtr)-1L);
  1495.         
  1496.     SetWRefCon(theDialog,(long)&theData);
  1497.     do
  1498.         ModalDialog(PasswordFilter,&item);
  1499.     while (item!=ok&&item!=cancel);
  1500.     DisposeDialog(theDialog);
  1501.     
  1502.     if (!hasPassword) {
  1503.         strcpy(password,oldPassword);
  1504.         oldPassword[0] = 0;
  1505.     }
  1506.         
  1507.     return (item==ok);
  1508. }
  1509.  
  1510.  
  1511. pascal Boolean PasswordFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit)
  1512. {
  1513.     DialogPeek dPeek;
  1514.     char theChar;
  1515.     short selStart,selEnd;
  1516.     PasswordDialogData *theData;
  1517.     char *theStr;
  1518.     short iType;
  1519.     Handle iHndl;
  1520.     Rect iRect;
  1521.     
  1522.     dPeek = (DialogPeek) theDialog;
  1523.     if (!dPeek)
  1524.         return false;
  1525.  
  1526.     theData = (PasswordDialogData *)GetWRefCon(theDialog);
  1527.     if ((dPeek->editField+1)==kOldPasswordItem)
  1528.         theStr = theData->oldPassword;
  1529.     else if ((dPeek->editField+1)==kNewPasswordItem)
  1530.         theStr = theData->password;
  1531.     else
  1532.         theStr = nil;
  1533.         
  1534.     switch (theEvent->what) {
  1535.         case keyDown:
  1536.         case autoKey:
  1537.             theChar = theEvent->message & charCodeMask;
  1538.             selStart = (**(dPeek->textH)).selStart;
  1539.             selEnd = (**(dPeek->textH)).selEnd;
  1540.             if (selEnd>strlen(theStr))
  1541.                 selEnd = strlen(theStr);
  1542.             switch (theChar) {
  1543.                 case 0x08:        /* backspace */
  1544.                     if (selStart == selEnd) {
  1545.                         if (selStart > 0)
  1546.                             BlockMove((Ptr)theStr + selStart,(Ptr)theStr + selStart-1,strlen(theStr)-selStart+1);
  1547.                     }
  1548.                     else
  1549.                         BlockMove((Ptr)theStr + selEnd,(Ptr)theStr + selStart,strlen(theStr)-selEnd+1);
  1550.                     break;
  1551.                 case 0x0d:    /* CR     */
  1552.                 case 0x03:    /* enter */
  1553.                     *itemHit = ok;
  1554.                     GetDItem(theDialog,ok,&iType,&iHndl,&iRect);
  1555.                     HiliteControl((ControlHandle)iHndl,inButton);
  1556.                     return true;
  1557.                     break;
  1558.                 case 0x09:    /* tab     */
  1559.                 case 0x1c:    /* left */
  1560.                 case 0x1d:    /* right */
  1561.                 case 0x1e:    /* up     */
  1562.                 case 0x1f:    /* down */
  1563.                     return false;
  1564.                     break;
  1565.                 case 0x1b:
  1566.                     *itemHit = cancel;
  1567.                     GetDItem(theDialog,cancel,&iType,&iHndl,&iRect);
  1568.                     HiliteControl((ControlHandle)iHndl,inButton);
  1569.                     return true;
  1570.                     break;
  1571.                 case '.':
  1572.                     if ((theEvent->modifiers & cmdKey) != 0) {
  1573.                         *itemHit = cancel;
  1574.                         GetDItem(theDialog,cancel,&iType,&iHndl,&iRect);
  1575.                         HiliteControl((ControlHandle)iHndl,inButton);
  1576.                         return true;
  1577.                     }
  1578.                 default:
  1579.                     BlockMove((Ptr)theStr+selEnd,(Ptr)theStr+selStart+1,strlen(theStr)-selEnd+1);
  1580.                     *(theStr+selStart) = theChar;
  1581.                     theEvent->message = 0xffffff00 + '•';
  1582.                     return false;
  1583.                     break;
  1584.             }
  1585.             break;
  1586.     }
  1587.     
  1588.     return false;
  1589. }
  1590.  
  1591.  
  1592. //---------------------------------------------------------------------------------------
  1593. //---------------------------------------------------------------------------------------
  1594.  
  1595. void DoError(OSErr err)
  1596. {
  1597.     #pragma unused (err)
  1598.     #ifdef kDEBUG
  1599.     DebugStr("\perror");
  1600.     #else
  1601.     SysBeep(1);
  1602.     #endif
  1603. }